package repository

import (
	"boy-go/modules/system/aspect"
	"boy-go/modules/system/model"
	"boy-go/modules/system/vo"
	"boy-go/pkg/db"
	"boy-go/pkg/request"
	"fmt"
	"gorm.io/gorm"
	"strconv"
)

type SysUserRepository struct {
	DB *gorm.DB
}

func NewSysUserRepository() *SysUserRepository {
	return &SysUserRepository{
		DB: db.GetMasterDB(),
	}
}
func (r *SysUserRepository) GetById(userId int64) (*model.SysUser, error) {
	db := r.DB
	m := &model.SysUser{}
	err := db.Model(&model.SysUser{}).Where("user_id = ? and del_flag = '0'", userId).First(m).Error
	if err != nil {
		return nil, err
	}
	return m, nil
}
func (r *SysUserRepository) GetByName(username string) (*model.SysUser, error) {
	db := r.DB
	m := &model.SysUser{}
	err := db.Model(&model.SysUser{}).Where("user_name = ? and del_flag = '0'", username).First(m).Error
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (r *SysUserRepository) List(query *vo.QuerySysUserReq, pageReq *request.PageRequest) ([]*model.SysUser, int64, error) {
	selectSQl := "select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader "
	selectCountSQl := "select count(0) "
	whereSql := "from sys_user u left join sys_dept d on u.dept_id = d.dept_id where u.del_flag = '0'"
	tx := r.DB
	if query != nil {
		if query.UserId != nil {
			whereSql += " and u.user_id = " + strconv.FormatInt(*query.UserId, 10)
		}
		if query.UserName != nil {
			whereSql += " and u.user_name like '%" + *query.NickName + "%'"
		}
		if query.NickName != nil {
			whereSql += " and u.nick_name like '%" + *query.NickName + "%'"
		}
		if query.Email != nil {
			whereSql += " and u.email like '%" + *query.Email + "%'"
		}
		if query.PhoneNumber != nil {
			whereSql += " and u.phonenumber like '%" + *query.PhoneNumber + "%'"
		}
		if query.Sex != nil {
			whereSql += " and u.sex = '" + *query.Sex + "'"
		}
		if query.Status != nil {
			whereSql += " and u.status = '" + *query.Status + "'"
		}
		if query.Params != nil {
			val, have := query.Params["beginTime"]
			if have {
				beginTime := val.(string)
				whereSql += (" AND date_format(u.create_time,'%Y%m%d') >= date_format('" + beginTime + "','%Y%m%d')")
			}
			val, have = query.Params["endTime"]
			if have {
				endTime := val.(string)
				whereSql += (" AND date_format(u.create_time,'%Y%m%d') <= date_format('" + endTime + "','%Y%m%d')")
			}
		}
		if query.DeptId != nil && *query.DeptId != 0 {
			whereSql += fmt.Sprintf(" and (u.dept_id = %d OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(%d, ancestors) ))", *query.DeptId, *query.DeptId)
		}
	}
	list := make([]*model.SysUser, 0)
	if pageReq != nil {
		sql := selectCountSQl + whereSql
		var total int64
		if err := tx.Raw(sql).Count(&total).Error; err != nil {
			return nil, 0, err
		}
		sql = selectSQl + whereSql
		aspect.HandleDataScope(&sql, "d", "u")
		db.BuildPageAndOrderSQL(&sql, pageReq, "")
		err := tx.Raw(sql).Scan(&list).Error
		return list, total, err
	} else {
		sql := selectSQl + whereSql
		aspect.HandleDataScope(&sql, "d", "u")
		err := tx.Raw(sql).Scan(&list).Error
		if err != nil {
			return nil, 0, err
		}
		return list, int64(len(list)), err
	}
}

// Save 添加
func (r *SysUserRepository) Save(m *model.SysUser) error {
	return r.DB.Model(&model.SysUser{}).Create(m).Error
}

// Update 更新
func (r *SysUserRepository) Update(m *model.SysUser) error {
	err := r.DB.Model(&model.SysUser{}).Where("user_id = ?", m.UserId).Omit("user_id").Updates(&m).Error
	return err
}

// Delete 删除
func (r *SysUserRepository) Delete(userId int64) error {
	return r.DB.Model(&model.SysUser{}).Where("user_id = ?", userId).Delete(&model.SysUser{}).Error
}

// DeleteBatch 批量删除
func (r *SysUserRepository) DeleteBatch(ids []interface{}) error {
	db := r.DB
	db = db.Where("(user_id)", ids)
	return db.Delete(&model.SysUser{}).Error
}

func (r *SysUserRepository) CheckUserNameUnique(userName *string) (*model.SysUser, error) {
	m := &model.SysUser{}
	sql := "select user_id, user_name from sys_user where user_name = ? and del_flag = '0' limit 1"
	err := r.DB.Raw(sql, userName).Scan(m).Error
	if err != nil {
		return nil, err
	}
	return m, nil
}
func (r *SysUserRepository) CheckPhoneUnique(phonenumber *string) (*model.SysUser, error) {
	m := &model.SysUser{}
	sql := "select user_id, phonenumber from sys_user where phonenumber = ? and del_flag = '0' limit 1"
	err := r.DB.Raw(sql, phonenumber).Scan(m).Error
	if err != nil {
		return nil, err
	}
	return m, nil
}
func (r *SysUserRepository) CheckEmailUnique(email *string) (*model.SysUser, error) {
	m := &model.SysUser{}
	sql := "select user_id, email from sys_user where email = #? and del_flag = '0' limit 1"
	err := r.DB.Raw(sql, email).Scan(m).Error
	if err != nil {
		return nil, err
	}
	return m, nil
}

func (r *SysUserRepository) SelectAllocatedList(query *vo.QuerySysUserReq, pageReq *request.PageRequest) ([]*model.SysUser, int64, error) {
	tx := r.DB
	selectCountSQL := "select count(0) from sys_user u "
	selectSQL := "select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time from sys_user u "
	leftJoinSQL := " left join sys_dept d on u.dept_id = d.dept_id  left join sys_user_role ur on u.user_id = ur.user_id  left join sys_role r on r.role_id = ur.role_id "
	whereSQL := " where u.del_flag = '0' and r.role_id = " + fmt.Sprintf("%d", *query.RoleId)
	if query != nil {
		if query.UserName != nil {
			whereSQL += fmt.Sprintf(" and u.user_name like '%s'", "%"+*query.UserName+"%")
		}
		if query.PhoneNumber != nil {
			whereSQL += fmt.Sprintf(" and u.phonenumber like '%s'", "%"+*query.PhoneNumber+"%")
		}
	}
	list := make([]*model.SysUser, 0)
	if pageReq != nil {
		var total int64
		sql := selectCountSQL + leftJoinSQL + whereSQL
		err := tx.Raw(sql).Count(&total).Error
		if err != nil {
			return nil, total, err
		}
		sql = selectSQL + leftJoinSQL + whereSQL
		aspect.HandleDataScope(&sql, "d", "u")
		db.BuildPageAndOrderSQL(&sql, pageReq, "")
		err = tx.Raw(sql).Find(&list).Error
		if err != nil {
			return nil, 0, err
		}
		return list, total, nil
	} else {
		sql := selectSQL + leftJoinSQL + whereSQL
		aspect.HandleDataScope(&sql, "d", "u")
		err := tx.Raw(sql).Find(&list).Error
		if err != nil {
			return nil, 0, err
		}
		return list, int64(len(list)), nil
	}
}
func (r *SysUserRepository) SelectUnAllocatedList(query *vo.QuerySysUserReq, pageReq *request.PageRequest) ([]*model.SysUser, int64, error) {
	tx := r.DB
	selectCountSQL := "select count(0) from sys_user u "
	selectSQL := "select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time from sys_user u "
	leftJoinSQL := " left join sys_dept d on u.dept_id = d.dept_id  left join sys_user_role ur on u.user_id = ur.user_id  left join sys_role r on r.role_id = ur.role_id "
	whereSQL := fmt.Sprintf(" where u.del_flag = '0' and (r.role_id != %d or r.role_id IS NULL)", *query.RoleId)
	whereSQL += fmt.Sprintf(" and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = %d)", *query.RoleId)
	if query != nil {
		if query.UserName != nil {
			whereSQL += fmt.Sprintf(" and u.user_name like '%s'", "%"+*query.UserName+"%")
		}
		if query.PhoneNumber != nil {
			whereSQL += fmt.Sprintf(" and u.phonenumber like '%s'", "%"+*query.PhoneNumber+"%")
		}
	}
	list := make([]*model.SysUser, 0)
	if pageReq != nil {
		var total int64
		sql := selectCountSQL + leftJoinSQL + whereSQL
		err := tx.Raw(sql).Count(&total).Error
		if err != nil {
			return nil, total, err
		}
		sql = selectSQL + leftJoinSQL + whereSQL
		aspect.HandleDataScope(&sql, "d", "u")
		db.BuildPageAndOrderSQL(&sql, pageReq, "")
		err = tx.Raw(sql).Find(&list).Error
		if err != nil {
			return nil, 0, err
		}
		return list, total, nil
	} else {
		sql := selectSQL + leftJoinSQL + whereSQL
		aspect.HandleDataScope(&sql, "d", "u")
		err := tx.Raw(sql).Find(&list).Error
		if err != nil {
			return nil, 0, err
		}
		return list, int64(len(list)), nil
	}
}
